/**
 * Created by Richard Radlherr.
 * Date: 20.06.2006 19:53
 */

using System;
using TagTool.OpenGL;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Windows.Forms;
using TagTool.Core;

namespace TagTool.Components
{
	/**
	 * This class represents a Stage - it creates the open GL Content.
	 * Furthermor it controls the window's framerate and rendering incoming
	 * content.
	 * The StageForm ist used by the Projectornode which uses the StageManger
	 * the cretae the Stage.
	 * TODO: check out which Blending- Capabilities are available ob the Hardware
	 * because due to set up the values to e.g. GL_SRC_COLOR the creation of the GL
	 * context crashes on some machines.
	 * TODO: the same as above but for other settings.
	 */
	public class StageForm : Model, IStage
	{

		private float[] LightAmbient = {0.5f, 0.5f, 0.5f, 1.0f};
		private float[] LightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
		private float[] LightPosition = {0.0f, 0.0f, 2.0f, 1.0f};

		private uint[] texture = new uint[3];

		Timer timer = new Timer();
		
		TagTool.OpenGL.View view;
		
		// the content to be rendered
		RenderableNode content = null;

		// the Manager controlling this object
		StageManager manager;

		/**
		 * The contructor takts the managing object
		 */
		public StageForm(StageManager manager, String name) : base(name)
		{
			App app = new App(this);
			this.view = app.View;
			
			this.manager = manager;
			//manager.AddStage(this);

			timer.Interval = 30;
		}

        public bool FullScreen
        {
            get { return this.App.IsFullscreen; }
            set
            {
                if (FullScreen != value)
                {
                	ShutDown();
                    this.App.ToggleFullscreen();
                    view = this.App.View;
                    Initialize();
                    App.Form.Invalidate();
                }
            }
        }
		
		private void OnTick(Object sender, EventArgs e)
		{
			view.Redraw();
		}
		
		protected override void ShutDown()
		{
			timer.Stop();
			timer.Tick -= new EventHandler(this.OnTick);
		}

		public override void Initialize() {
			glShadeModel(GL_FLAT);
			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
			glClearDepth(1.0f);
			glEnable(GL_DEPTH_TEST);
			glDisable(GL_POLYGON_SMOOTH);
			glEnable(GL_LINE_SMOOTH);
			
			glDepthFunc(GL_LEQUAL);
			
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	
			
			glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);	
			glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);	
			glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
			
			glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
			glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
			glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
			
			glEnable(GL_POLYGON_SMOOTH, false);
			//glEnable(GL_LINE_SMOOTH, true);
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			
			glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            //glBlendFunc(GL_SRC_COLOR, GL_ONE);	

           
            timer.Tick += new EventHandler(this.OnTick);
			timer.Start();
			
		}
		
		public RenderableNode Content
		{
			get { return content; }
			set { content = value; }
		}

		/**
		 * Draw the content of the attached RenderingNode
		 */
		public override void Draw() 
		{
		 	view.GrabContext();
            Reshape(this.App.Form.ClientSize.Width, this.App.Form.ClientSize.Width);
		 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glLoadIdentity();
			gluLookAt(0.0, 0.0, -30.0,  0.0, 0.0, 0.0,  0.0, -1.0, 0.0);

			if (content != null)
			{
				content.Render();
			}
			
		}
		
		public void Resize(int x, int y, int w, int h)
		{
			if (! FullScreen)
			{
				App.Form.SetBounds(x, y, w, h);
				App.Form.Invalidate();
			}
		}
		
		public void Invalidate()
		{
			App.Form.Invalidate();
		}

		public override void Reshape(int width, int height) 
		{
			if(height == 0) {															// If Height Is 0
				height = 1;																// Set To 1 To Prevent A Divide By Zero
			}

			glViewport(0, 0, width, height);											// Reset The Current Viewport
			glMatrixMode(GL_PROJECTION);												// Select The Projection Matris
			glLoadIdentity();															// Reset The Projection Matrix

			// Set Up A Perspective Projection Matrix 
			gluPerspective(App.FovY, (float) width / (float) height, App.NearClippingPlane, App.FarClippingPlane);
			
			glMatrixMode(GL_MODELVIEW);													// Select The Modelview Matrix
			glLoadIdentity();															// Reset The Modelview Matrix
		}
	}
	
}
